pub(crate) mod auto_abort;
pub mod helper_types;
pub use maybe_deser_owned;
pub use serde;

use crate::courier::codec::{Decoded, FromSliceDeserializer};
use tokio_util::bytes::Bytes;
use maybe_deser_owned::VariantMaybeDeserOwned;
use serde::Deserialize;
use std::ops::Deref;

// NOTE: This structure isn't self-referential since we store (essentially) an
// references counted pointer to the real source data rather than the data
// itself.
#[derive(Debug)]
pub struct OwnedOrRefWithSrc<R> {
    // NOTE: `inner` should be dropped first
    inner: R,
    src: Option<Bytes>,
}

impl<R> OwnedOrRefWithSrc<R> {
    /// # Safety
    ///
    /// The caller should guarantee that if the inner type contain references
    /// to the outside world, the inner type should be dropped before the source
    /// type.
    pub unsafe fn into_inner(self) -> (R, Option<Bytes>) {
        (self.inner, self.src)
    }

    /// # Safety
    ///
    /// The caller must make sure that the error type does not
    /// contain references to the original source.
    pub unsafe fn try_map_inner<O, E, F: FnOnce(R) -> Result<O, E>>(
        self,
        f: F,
    ) -> Result<OwnedOrRefWithSrc<O>, E> {
        let src = self.src;
        let inner = f(self.inner)?;
        Ok(OwnedOrRefWithSrc {
            inner,
            src,
        })
    }

    pub fn new_owned(data: R) -> Self {
        Self {
            src: None,
            inner: data,
        }
    }
    pub fn new_refed(src: Bytes, data: R) -> Self {
        Self {
            src: Some(src),
            inner: data,
        }
    }
    pub fn assert_owned(self) -> R {
        if self.src.is_none() {
            self.inner
        } else {
            panic!("Assert fail: The inner type contains references!")
        }
    }
    pub fn assert_ref_with_src(self) -> (R, Bytes) {
        if let Some(src) = self.src {
            (self.inner, src)
        } else {
            panic!("Assert fail: The inner type owns all of its data!")
        }
    }
}
impl<T> Deref for OwnedOrRefWithSrc<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

#[inline]
fn deser_with_src_bytes<T, D>(deser: &D, src: Bytes) -> Result<OwnedOrRefWithSrc<T>, D::Err>
where
    D: FromSliceDeserializer,
    T: Deserialize<'static> + VariantMaybeDeserOwned,
{
    let bytes: &[u8] = &src;
    // SAFETY:
    // We only expand the lifetime, the safety of this expansion depends on:
    // 1. `deserialize_from_slice<'a, 'de>(&'a self, src: &'de [u8])`
    //    does not leak the reference to `src` into outside world.
    // 2. `variant_is_deser_owned` implementation does not leak
    //    reference to `self` into outside world.
    // 3. `variant_is_deser_owned` contains correct implementation,
    //    i.e. when it returns `true`, the value desered indeed does
    //    not contain any reference to outside world.
    let bytes: &'static [u8] = unsafe { std::mem::transmute(bytes) };
    let res = deser.deserialize_from_slice::<T>(bytes)?;
    if res.variant_is_deser_owned() {
        Ok(OwnedOrRefWithSrc::new_owned(res))
    } else {
        Ok(OwnedOrRefWithSrc::new_refed(src, res))
    }
}

#[inline]
pub(crate) fn deser_from_decoded<T, D>(
    decoded: Decoded<T>,
    deser: &D,
) -> Result<OwnedOrRefWithSrc<T>, D::Err>
where
    D: FromSliceDeserializer,
    T: Deserialize<'static> + VariantMaybeDeserOwned,
{
    match decoded {
        Decoded::Empty => deser_with_src_bytes(deser, Bytes::new()),
        Decoded::Source(src) => deser_with_src_bytes(deser, src),
        Decoded::Deserialzed(data) => Ok(OwnedOrRefWithSrc::new_owned(data)),
    }
}
